#include "M051Series.h"
#include "Uart0_FIFO.h"


/**************************************************************************/
#include <stdio.h>
#include "M051Series.h"
#include "UART_FIFO.h"


uint8_t g_u8UAFIFO_RxFifo[UAFIFO_RX_FIFO_SIZE] = {0};
uint8_t g_u8UAFIFO_TxFifo[UAFIFO_RX_FIFO_SIZE] = {0};
int32_t g_i32UAFIFO_RxFifoHead = 0;
int32_t g_i32UAFIFO_RxFifoTail = 0;
int32_t g_i32UAFIFO_TxFifoHead = 0;
int32_t g_i32UAFIFO_TxFifoTail = 0;


void UART0_IRQHandler(void)
{
    uint8_t bInChar;
    uint32_t u32IntStatus;
    int32_t i32Tmp;

    u32IntStatus = UART0->ISR;
    if((u32IntStatus & UART_ISR_RDA_IF_Msk) || (u32IntStatus & UART_ISR_TOUT_IF_Msk))
    {
        /* Receiver FIFO threashold level is reached or Rx time out */

        /* Get all the input characters */
        while((UART0->FSR & UART_FSR_RX_EMPTY_Msk) == 0)
        {
            /* Get the character from UART hardware FIFO */
            bInChar = UART0->DATA;

            i32Tmp = g_i32UAFIFO_RxFifoHead + 1;
            _UAFIFO_RXP_ROUND(i32Tmp);
             
            /* Check if buffer full */
            if(i32Tmp != g_i32UAFIFO_TxFifoTail)
            {
                /* Enqueue the character */
                g_u8UAFIFO_RxFifo[g_i32UAFIFO_RxFifoHead++] = bInChar;
                _UAFIFO_RXP_ROUND(g_i32UAFIFO_RxFifoHead);
            }
            else
            {
                /* FIFO over run */
            }           
        }
    }
    
    if(u32IntStatus & UART_ISR_THRE_IF_Msk)
    {   
        while(g_i32UAFIFO_TxFifoHead != g_i32UAFIFO_TxFifoTail)
        {
            /* Fill the Tx hardware FIFO */
            UART0->DATA = g_u8UAFIFO_TxFifo[g_i32UAFIFO_TxFifoTail++];
            _UAFIFO_TXP_ROUND(g_i32UAFIFO_TxFifoTail);

            /* check if hardware FIFO full */
            if(UART0->FSR & UART_FSR_TX_FULL_Msk)
                break;
        }
        
        if(g_i32UAFIFO_TxFifoHead == g_i32UAFIFO_TxFifoTail)
        {
            /* No more data, just stop Tx (Stop work) */
            UART0->IER &= ~UART_IER_THRE_IEN_Msk;
        }
    }
}

void UAFIFO_InitUART0(void)
{
/*---------------------------------------------------------------------------------------------------------*/
/* Init UART                                                                                               */
/*---------------------------------------------------------------------------------------------------------*/
    
    // Assign baud rate according to system clock 
    UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_DIV_MODE2(50000000, 115200);
    
    // Data format
    _UART_SET_DATA_FORMAT(UART0, UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1);

    // Enable UART interrupts
    UART0->IER = UART_IER_TIME_OUT_EN_Msk | UART_IER_BUF_ERR_IEN_Msk | UART_IER_RTO_IEN_Msk | 
                 UART_IER_RLS_IEN_Msk | UART_IER_THRE_IEN_Msk | UART_IER_RDA_IEN_Msk;

    // Set Rx FIFO trigger level and reset Tx, Rx FIFO
    UART0->FCR = UART_FCR_RFITL_14BYTES | UART_FCR_TFR_Msk | UART_FCR_RFR_Msk;


    NVIC_EnableIRQ(UART0_IRQn);
}

void UAFIFO_ResetFifo(void)
{
    g_i32UAFIFO_RxFifoHead = 0;
    g_i32UAFIFO_RxFifoTail = 0;
    g_i32UAFIFO_TxFifoHead = 0;
    g_i32UAFIFO_RxFifoTail = 0;
}

void UAFIFO_TriggerTx(void)
{
    /* Check if Tx FIFO empty */
    if(g_i32UAFIFO_TxFifoHead == g_i32UAFIFO_TxFifoTail)
        return;

    /* Check if Tx interrupt is disabled */
    if((UART0->IER & UART_IER_THRE_IEN_Msk) == 0)
    {
        /* Eanble THRE_IEN: Transmit holding register empty interrupt */
        UART0->IER |= UART_IER_THRE_IEN_Msk;
    }
}



